package us.feng.tinyspring.beans.factory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import us.feng.tinyspring.beans.BeanDefinition;
import us.feng.tinyspring.beans.BeanException;
import us.feng.tinyspring.beans.BeanWrapper;
import us.feng.tinyspring.beans.BeanWrapperImpl;
import us.feng.tinyspring.beans.PropertyValue;
import us.feng.tinyspring.beans.PropertyValues;
import us.feng.tinyspring.beans.factory.support.BeanDefinitionValueResolver;
import us.feng.tinyspring.beans.factory.support.InstantiationStrategy;
import us.feng.tinyspring.beans.factory.support.SimpleInstantiationStrategy;

public class DefaultListableBeanFactory extends AbstractBeanFactory{
	
	private final Map<String, Object> beanInstanceCache = new ConcurrentHashMap<String, Object>();
	
	private static final Logger LOGGER=LoggerFactory.getLogger(DefaultListableBeanFactory.class);

	@Override
	protected void applyPropertyValues(String beanName, BeanDefinition mbd, Object bean, PropertyValues pvs) {
		
		BeanDefinitionValueResolver valueResolver=new BeanDefinitionValueResolver(this, beanName, mbd, null);
		PropertyValue []propertyValues=pvs.getPropertyValues();
		for(PropertyValue pv:propertyValues){
			Object originObject=pv.getValue();
			// 转化对象（ref）
			Object resolveObject=valueResolver.resolveValueIfNecessary(mbd, originObject);
			
			LOGGER.debug("Resolve property value object [{}]->[{}] of Bean [{}]",originObject.getClass(),resolveObject.getClass(),bean.getClass());
			if(resolveObject!=originObject){
				pvs.removePropertyValue(pv);
				pvs.addPropertyValue(new PropertyValue(pv.getName(), resolveObject));
			}
		}
		
		
		BeanWrapper bw=new BeanWrapperImpl(bean);
		bw.setPropertyValues(pvs);
	}

	@Override
	public Object createBean(BeanDefinition bd,String beanName) {
		// 实例化
		InstantiationStrategy strategy=new SimpleInstantiationStrategy();
		Object bean=strategy.instantiate(bd, beanName);

		/** 先创建缓存，后注入属性  */
		// 存入缓存
		beanInstanceCache.put(beanName,bean);
		
		// 注入属性
		applyPropertyValues(beanName, bd, bean, getBeanDefinition(beanName).getPropertyValues());
		return bean;
	}
	
	public Object getBean(String beanName) throws BeanException {
		Object object=beanInstanceCache.get(beanName);
		if(null==object){
			BeanDefinition bd=getBeanDefinition(beanName);
			if(null==bd){
				throw new BeanException("No bean named [ " + beanName + " ] is defined");
			}
			
			object=createBean(bd,beanName);
		}
		return object;
	}

	@Override
	public void preInstantiateSingletons() {
		// TODO Auto-generated method stub
		
	}

}
